# This file is part of trytond-pcw-stock module for Tryton. 
# The COPYRIGHT file at the top level of this repository contains 
# the full copyright notices and license terms.

from trytond.model import Workflow, ModelView, ModelSQL, fields
from trytond.pyson import If, Not, Equal, Eval, Or, Bool
from trytond.transaction import Transaction
from trytond.pool import Pool, PoolMeta

__all__ = ['Snapshot', 'SnapshotLine']
__metaclass__ = PoolMeta

class Snapshot(Workflow, ModelSQL, ModelView):
    'Pcw Stock Snapshot'
    __name__ = 'pcw.stock.snapshot'

    date = fields.Date('Date', required=True, select=True, states={
            'readonly': Or(Not(Equal(Eval('state'), 'draft')),
                Bool(Eval('lines'))),
            },
        depends=['state', 'lines'])
    description = fields.Char('Descripcion', size=None, 
        states={'readonly': Eval('state') != 'draft',},
        depends=['state'])
    lines = fields.One2Many('pcw.stock.snapshot.line', 'snapshot', 'Lines', 
        states={'readonly': True,},
        depends=['sate'])
    company = fields.Many2One('company.company', 'Company', required=True,
        states={
            'readonly': True,
            },
        depends=['state', 'lines'])
    state = fields.Selection([
        ('draft', 'Draft'),
        ('done', 'Done'),
        ('cancel', 'Canceled'),
        ], 'State', readonly=True, select=True)


    @classmethod
    def __setup__(cls):
        super(Snapshot, cls).__setup__()
        cls._order.insert(0, ('date', 'DESC'))

        cls._error_messages.update({
                'delete_cancel': ('Snapshot "%s" must be cancelled before '
                    'deletion.'),
                'snapshot_exists': ('Snapshot with date >= "%s" exists.'),
                'snapshot_has_lines': ('Snapshot already has lines.'),
                'date_not_set': ('Date must be set.'),
                })

        cls._transitions |= set((
                ('draft', 'done'),
                ('done', 'cancel'),
                ('cancel', 'draft'),
                ))
        cls._buttons.update({
                'cancel': {
                    'invisible': Eval('state').in_(['cancel', 'draft']),
                    },
                'draft': {
                    'invisible': ~Eval('state').in_(['cancel']),
                    'icon': If(Eval('state') == 'cancel', 'tryton-clear','tryton-go-previous'),
                    },
                'confirm': {
                    'invisible': Eval('state').in_(['done', 'cancel']),
                    },
                'get_all_products': {
                    'readonly': Eval('state') != 'draft',
                    },
                })

    @staticmethod
    def default_state():
        return 'draft'

    @staticmethod
    def default_company():
        return Transaction().context.get('company')

    @classmethod
    def delete(cls, snapshots):
        for ss in snapshots:
            if ss.state == 'done':
                cls.raise_user_error('delete_cancel', error_args=(str(ss.date),))                
        super(Snapshot, cls).delete(snapshots)

    @staticmethod
    def snapshot_exists(date, company_id, ignore_id=None):
        Ss = Pool().get('pcw.stock.snapshot')
        search_list=[('date', '>=', date), ('state', '=', 'done'), ('company','=',company_id)]
        if ignore_id:
             search_list.append(('id','!=',ignore_id))

        orders = Ss.search(search_list, order=[('date','DESC')], limit=1)

        if orders:
            return True
        return False 

    @classmethod
    @ModelView.button
    @Workflow.transition('draft')
    def draft(cls, orders):
        pass

    @classmethod
    @ModelView.button
    @Workflow.transition('done')
    def confirm(cls, snapshots):
        obj_line = Pool().get('pcw.stock.snapshot.line')
        for ss in snapshots:
            if ss.snapshot_exists(ss.date, ss.company.id, ss.id):
                cls.raise_user_error('snapshot_exists', error_args=(str(ss.date),))
            lines = obj_line.search([('snapshot','=',ss.id)])  
            obj_line.delete(lines)
        cls.get_all_products(snapshots)

    @classmethod
    @ModelView.button
    @Workflow.transition('cancel')
    def cancel(cls, snapshots):
        for ss in snapshots:
            if ss.snapshot_exists(ss.date, ss.company.id, ss.id):
                cls.raise_user_error('snapshot_exists', error_args=(str(ss.date),))

    @classmethod
    def get_all_products(cls, snapshots):
        Product = Pool().get('product.product')
        Line = Pool().get('pcw.stock.snapshot.line')
        prds = Product.search([('active','=',True)])
        if not prds:
            return 

        for ss in snapshots:
            if ss.state == 'done':
                continue 

            if ss.lines:   
                cls.raise_user_error('snapshot_has_lines',)
            if not ss.date:   
                cls.raise_user_error('date_not_set',)
            if ss.snapshot_exists(ss.date, ss.company.id, ss.id):
                cls.raise_user_error('snapshot_exists', error_args=(str(ss.date),))
            for pr in prds:
                if pr.type == 'service':
                    continue
                line = Line() 
                line.snapshot = ss
                line.product = pr
                line.quantity = pr.get_quantity_by_date(date_end=ss.date)
                line.average_cost = pr.get_average_cost()
                line.last_cost = pr.get_last_cost()
                line.save()  


class SnapshotLine(ModelSQL, ModelView):
    'Pcw Stock Snapshot Line'
    __name__ = 'pcw.stock.snapshot.line'

    snapshot = fields.Many2One('pcw.stock.snapshot', 'Snapshot', required=True,
            ondelete='CASCADE')
    product = fields.Many2One('product.product', 'Product', required=True, readonly=True,
        domain=[
            ('type', '!=', 'service'),
            ],)
    quantity = fields.Float('Quantity', required=True, readonly=True, digits=(16, 4))
    uom = fields.Function( fields.Many2One('product.uom', 'Uom'), 'on_change_with_uom')
    average_cost = fields.Numeric('Average cost', required=True, readonly=True, digits=(16, 4))
    last_cost = fields.Numeric('Last cost', required=True, readonly=True, digits=(16, 4))

    @classmethod
    def __setup__(cls):
        super(SnapshotLine, cls).__setup__()

        cls._error_messages.update({
                'date_not_set': ('Date must be set.'),
                })

    def on_change_with_uom(self, name=None):
        if self.product:
            return self.product.default_uom.id

